package com.fingard.dsp.bank.directbank.hsbc02;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.db.JDBCHelper;
import com.fingard.dsp.bank.directbank.bankInterface.ISinglePay;
import com.fingard.dsp.bank.reqrespobj.single.*;
import com.fingard.dsp.bank.reqrespobj.single.detail.RetAtsSglDetail;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import java.sql.Connection;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * 汇丰银行api单笔支付及付款结果查询
 */
public class HSBC02SinglePay extends HSBC02Base implements ISinglePay {

    private static final String INSERTSEQ = "INSERT INTO REQSEQIDMAPPING(URID,BANKCODE,TRANSDATE,REQSEQID,BANKREQSEQID) values (?,?,?,?,?);";
    private static final String SELECTSEQ = "SELECT BANKREQSEQID FROM REQSEQIDMAPPING WHERE REQSEQID=? AND BANKCODE=?;";

    /**
     * 单笔付款
     * @param p_req1908
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsSingle d_1908_SglPay(ReqSingle p_req1908) throws Exception {
        RetAtsSingle retAts = new RetAtsSingle(p_req1908.reqHeader);
        RetAtsSglDetail detail = new RetAtsSglDetail();
        Connection conn= null;
        try{
            //拼接付款请求报文
            XmlTextWriter xmlWriter = new XmlTextWriter();
            WriteCommonHeader(xmlWriter);
            xmlWriter.writeStartElement("GrpHdr");
            xmlWriter.writeElementString("MsgId", p_req1908.singleDetail.askNumber);
            String date = p_req1908.singleDetail.payDate + "T" + p_req1908.singleDetail.payTime;
            xmlWriter.writeElementString("CreDtTm", date);
            xmlWriter.writeStartElement("Authstn");
            xmlWriter.writeElementString("Cd", "AUTH");
            xmlWriter.writeEndElement();
            xmlWriter.writeElementString("NbOfTxs", "1");
            xmlWriter.writeElementString("CtrlSum", p_req1908.singleDetail.payAmount);
            //发起方信息
            xmlWriter.writeStartElement("InitgPty");
            xmlWriter.writeStartElement("Id");
            xmlWriter.writeStartElement("OrgId");
            xmlWriter.writeStartElement("Othr");
            xmlWriter.writeElementString("Id",getBankConfig().getValueAsString("x-hsbc-profile-id"));//客户号
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            //付款信息
            xmlWriter.writeStartElement("PmtInf");
            xmlWriter.writeElementString("PmtInfId", p_req1908.singleDetail.askNumber);//流水号
            xmlWriter.writeElementString("PmtMtd", "TRF");
            //付款类型信息
            xmlWriter.writeStartElement("PmtTpInf");
            //xmlWriter.writeElementString("InstrPrty", "NORM");//优先级HIGH高、NORM正常
            xmlWriter.writeStartElement("SvcLvl");
            xmlWriter.writeElementString("Cd", "URGP");//URGP紧急付款、SDVA当天
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeElementString("ReqdExctnDt", p_req1908.singleDetail.payDate);
            //付款人信息
            xmlWriter.writeStartElement("Dbtr");
            String payName=p_req1908.singleDetail.payName;
            if(payName.length()>140){
                payName=payName.substring(0,140);
            }
            xmlWriter.writeElementString("Nm", payName);
            xmlWriter.writeStartElement("PstlAdr");
            String payActCtry=getBankConfig().getMapValueByKey("balanceAndConturyMapping",p_req1908.singleDetail.payAct);
            String recActCtry=getBankConfig().getMapValueByKey("balanceAndConturyMapping",p_req1908.singleDetail.recAct);
            xmlWriter.writeElementString("Ctry", payActCtry);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            //付款人账户信息
            xmlWriter.writeStartElement("DbtrAcct");
            xmlWriter.writeStartElement("Id");
            xmlWriter.writeStartElement("Othr");
            xmlWriter.writeElementString("Id", p_req1908.singleDetail.payAct);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeElementString("Ccy", convertCurToBank(p_req1908.singleDetail.payCur));
            xmlWriter.writeEndElement();
            //付款人银行信息
            xmlWriter.writeStartElement("DbtrAgt");
            xmlWriter.writeStartElement("FinInstnId");
            xmlWriter.writeElementString("BIC",
                    getBankConfig().getMapValueByKey("balanceAndSwiftMapping",p_req1908.singleDetail.payAct));//固定swiftcode
            //地址
            xmlWriter.writeStartElement("PstlAdr");
            xmlWriter.writeElementString("Ctry", payActCtry);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            //收款方交易信息
            xmlWriter.writeStartElement("CdtTrfTxInf");
            xmlWriter.writeStartElement("PmtId");
            xmlWriter.writeElementString("InstrId", p_req1908.singleDetail.askNumber);
            xmlWriter.writeElementString("EndToEndId", p_req1908.singleDetail.askNumber);
            xmlWriter.writeEndElement();
            xmlWriter.writeStartElement("Amt");
            String currency = convertCurToBank(p_req1908.singleDetail.recCur);
            xmlWriter.writeElementAttribute("InstdAmt",p_req1908.singleDetail.payAmount,"Ccy",currency);
            xmlWriter.writeEndElement();
            xmlWriter.writeElementString("ChrgBr","DEBT");//默认DEBT
            //收款人银行信息
            xmlWriter.writeStartElement("CdtrAgt");
            xmlWriter.writeStartElement("FinInstnId");
            if(StringHelper.hasAnyChar(p_req1908.singleDetail.recSwiftCode)){
                xmlWriter.writeElementString("BIC", p_req1908.singleDetail.recSwiftCode);
            }
            String recBnkName=p_req1908.singleDetail.cnapsName;
            if(recBnkName.length()>140){
                recBnkName=recBnkName.substring(0,140);
            }
            xmlWriter.writeElementString("Nm", recBnkName);
            //地址
            xmlWriter.writeStartElement("PstlAdr");
            xmlWriter.writeElementString("Ctry", recActCtry);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            //收款人信息
            xmlWriter.writeStartElement("Cdtr");
            xmlWriter.writeElementString("Nm", p_req1908.singleDetail.recName);
            //地址
            xmlWriter.writeStartElement("PstlAdr");
            xmlWriter.writeElementString("Ctry", recActCtry);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeStartElement("CdtrAcct");
            xmlWriter.writeStartElement("Id");
            xmlWriter.writeStartElement("Othr");
            xmlWriter.writeElementString("Id", p_req1908.singleDetail.recAct);
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            xmlWriter.writeEndElement();
            String ustrd=p_req1908.singleDetail.purpose;//用途
            if(StringHelper.hasAnyChar(ustrd)){
                xmlWriter.writeStartElement("RmtInf");
                xmlWriter.writeElementString("Ustrd",ustrd);
                xmlWriter.writeEndElement();
            }
            xmlWriter.writeEndDocument();
            //发送请求报文
            String[] bankResult = sendToBank(xmlWriter.toXmlString(),p_req1908.reqHeader.transType,p_req1908.reqHeader.commandCode,"paymentBase64");
            //处理响应报文
            if (bankResult[0].length() == 0) {
                if(bankResult[2].length()!=0){
                    JSONObject jsonRsp = JSONObject.parseObject(bankResult[2]);
                    //String rspCode=StringHelper.hasAnyChar(jsonRsp.getString("statusCode"))
                    //      ?jsonRsp.getString("statusCode"):jsonRsp.getString("error");
                    String rspMesg=StringHelper.hasAnyChar(jsonRsp.getString("statusDesc"))
                            ?jsonRsp.getString("statusDesc"):jsonRsp.getString("description");
                    String bankSeqId=jsonRsp.getString("referenceId");
                    if(StringHelper.hasAnyChar(bankSeqId)){
                        //记录ats支付流水号对应的银行支付流水号，供查询状态接口使用
                        conn= FGBiz.getLocalDbConn();
                        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                        WriteBankLogLn("支付流水号关联："+INSERTSEQ+"参数值："+uuid+","+p_req1908.reqHeader.bankCode
                                +","+Format.Date8Format.format(new Date())+","+ p_req1908.singleDetail.askNumber+","+ bankSeqId);
                        JDBCHelper.update(conn, INSERTSEQ, new Object[]{uuid, p_req1908.reqHeader.bankCode,
                                Format.Date8Format.format(new Date()), p_req1908.singleDetail.askNumber, bankSeqId});
                    }
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(bankResult[1],tmpSbMsg);
                    if(tmpBkReader!=null) {
                        String transRspMsg=tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/StsRsnInf/AddtlInf");
                        if(tmpBkReader.getFirstText("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts")!=null){
                            String reqSeqId=tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts/TxInfAndSts/OrgnlEndToEndId");
                            detail.respCode = "0";
                            detail.respInfo = StringHelper.isNullOrEmpty(transRspMsg)?rspMesg:transRspMsg;
                            detail.reqSeqID = reqSeqId;
                            detail.transState = tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts/TxInfAndSts/TxSts");
                            detail.payInfoCode = detail.transState;
                        }else if(tmpBkReader.getFirstText("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/GrpSts")!=null){
                            detail.respCode = "0";
                            detail.respInfo = StringHelper.isNullOrEmpty(transRspMsg)?rspMesg:transRspMsg;
                            detail.reqSeqID = p_req1908.singleDetail.askNumber;
                            detail.transState = tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/GrpSts");
                            detail.payInfoCode = detail.transState;
                        } else {
                            detail.respCode = "-1";
                            detail.respInfo = "返回报文异常："+tmpBkReader.getOriXmlString();
                        }
                    }else {
                        detail.respCode = "-1";
                        detail.respInfo = tmpSbMsg.toString();
                    }
                }else {
                    detail.respCode = "-1";
                    detail.respInfo = bankResult[1];
                }
            }else {
                detail.respCode = "-1";
                detail.respInfo = bankResult[1];
            }
        }catch (Exception e){
            detail.respCode = "-1";
            detail.respInfo = e.getMessage();
            e.printStackTrace();
            WriteBankLogLn("转账出现异常:"+e);
        }finally {
            if(conn!=null){
                conn.close();
            }
        }
        retAts.writeRetDetail(detail);
        return retAts;
    }

    /**
     * 单笔付款状态查询
     *
     * 付款结果判断：1、若交易存在于明细中，说明交易成功；
     * 2、其他结果（中间状态、失败状态）通过调用银行接口来获取。
     *
     * @param p_req1944
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsSingle d_1944_QrySglPay(ReqQrySingle p_req1944) throws Exception {
        RetAtsSingle retAts = new RetAtsSingle(p_req1944.reqHeader);
        RetAtsSglDetail detail = new RetAtsSglDetail();
        boolean isExistFlag=checkIsExistTransaction(p_req1944);
        if(isExistFlag){
            detail.respCode = "0";
            detail.respInfo = "Transaction exists in details";
            detail.reqSeqID = p_req1944.askNumber;
            detail.transState = "SUCCESS";
            detail.payInfoCode = detail.transState;
        }else {
            Connection conn=null;
            try{
                //拼接付款请求报文
                XmlTextWriter xmlWriter = new XmlTextWriter();
                xmlWriter.writeStartElement("StatusEnquiry");
                xmlWriter.writeElementString("ProfileID",getBankConfig().getValueAsString("x-hsbc-profile-id"));
                xmlWriter.writeStartElement("Key");
                conn=FGBiz.getLocalDbConn();
                Map<String, Object> selMap=JDBCHelper.execQuerySingle(conn,SELECTSEQ,new Object[]{p_req1944.askNumber,p_req1944.reqHeader.bankCode});
                if(selMap!=null && selMap.size()>0){
                    xmlWriter.writeElementString("ReferenceID",selMap.get("BANKREQSEQID").toString());
                }else {
                    detail.respCode ="-1";
                    detail.respInfo = "系统交易流水号关联映射异常，请检查";
                    retAts.writeRetDetail(detail);
                    return retAts;
                }
                xmlWriter.writeElementString("MessageID","",true);
                xmlWriter.writeElementString("BatchID","",true);
                xmlWriter.writeElementString("TransactionID","",true);
                xmlWriter.writeEndElement();
                xmlWriter.writeEndDocument();
                //发送请求报文
                String rspMesg="";
                String[] bankResult = sendToBank(xmlWriter.toXmlString(),p_req1944.reqHeader.transType,p_req1944.reqHeader.commandCode,"paymentEnquiryBase64");
                if(bankResult[0].length()==0){
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(bankResult[1],tmpSbMsg);
                    if(tmpBkReader!=null) {
                        String transRspMsg=tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/StsRsnInf/AddtlInf");
                        if(tmpBkReader.getFirstText("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts")!=null){
                            String reqSeqId=tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts/TxInfAndSts/OrgnlEndToEndId");
                            detail.respCode = "0";
                            detail.respInfo = StringHelper.isNullOrEmpty(transRspMsg)?rspMesg:transRspMsg;
                            detail.reqSeqID = reqSeqId;
                            detail.transState = tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlPmtInfAndSts/TxInfAndSts/TxSts");
                            detail.payInfoCode = detail.transState;
                        }else if(tmpBkReader.getFirstText("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/GrpSts")!=null){
                            detail.respCode = "0";
                            detail.respInfo = StringHelper.isNullOrEmpty(transRspMsg)?rspMesg:transRspMsg;
                            detail.reqSeqID = p_req1944.askNumber;
                            detail.transState = tmpBkReader.getFirstTextNotNull("/Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/GrpSts");
                            detail.payInfoCode = detail.transState;
                        } else {
                            detail.respCode = "-1";
                            detail.respInfo = "返回报文异常："+tmpBkReader.getOriXmlString();
                        }
                    }else {
                        detail.respCode = "-1";
                        detail.respInfo = tmpSbMsg.toString();
                    }
                }else {
                    detail.respCode = "-1";
                    detail.respInfo = bankResult[1];
                }
            }catch (Exception e){
                detail.respCode = "-1";
                detail.respInfo = e.getMessage();
            }finally {
                if(conn!=null){
                    conn.close();
                }
            }
        }
        retAts.writeRetDetail(detail);
        return retAts;
    }

    /**
     * 校验交易是否已存在明细数据中
     * @param p_req1944
     * @return
     */
    private boolean checkIsExistTransaction(ReqQrySingle p_req1944) throws Exception{
        //查询明细数据中是否存在交易
        boolean isExistFlag=false;
        String[] decryptRsp=qryTransactionJson(p_req1944.payAct,Format.Date10Format.format(p_req1944.getBgnDateTime()));
        if(decryptRsp[0].length()==0){
            JSONObject balanceBodyJson=JSONObject.parseObject(decryptRsp[1]);
            if(balanceBodyJson==null) {
                return isExistFlag;
            }
            JSONObject transactionsJson=balanceBodyJson.getJSONObject("transactions");
            if(transactionsJson==null) {
                return isExistFlag;
            }
            String actNum=transactionsJson.getString("requestorAccountId");
            if(!actNum.equals(p_req1944.payAct)){
                return isExistFlag;
            }
            //条数
            String count=transactionsJson.getString("statementCount");
            if(StringHelper.isNullOrEmpty(count) || Integer.parseInt(count)==0) {
                return isExistFlag;
            }
            JSONArray transationArray=transactionsJson.getJSONArray("transaction");
            if(transationArray==null || transationArray.size()==0) {
                return isExistFlag;
            }
            //匹配支付流水号确认交易结果
            for(int i=0;i<transationArray.size();i++){
                JSONObject transationJson=transationArray.getJSONObject(i);
                if(transactionsJson==null){
                    continue;
                }
                JSONObject items=transationJson.getJSONObject("items");
                if(items==null){
                    continue;
                }
                JSONObject transactionAmount=items.getJSONObject("transactionAmount");
                if(transactionAmount==null){
                    continue;
                }
                //银行交易状态
                String askNumber=items.getString("statementReference");
                if(p_req1944.askNumber.equals(askNumber)){
                    isExistFlag=true;
                    break;
                }
            }
        }
        return isExistFlag;
    }

    @Override
    public RetAtsSingleBat d_1908BAT_SglBatPay(ReqSingleBat p_req1908BAT) throws Exception {
        return null;
    }

    @Override
    public RetAtsSingleBat d_1944BAT_QrySglBatPay(ReqQrySingleBat p_req1944BAT) throws Exception {
        return null;
    }
}
